package cn.bj.brook.tkit;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import io.github.bluesbruce.BrQrCodeUtil;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author brook zhao
 * 二维码工具，包装google zxing sdk
 */
public class QrCodeUtil {

    /**
     * 向一个本地文件写入二维码图片，默认纠错率为低
     *
     * @param fullFilePath 文件的全路径
     * @param anyValue     任何需要变为二维码的字符串
     * @param edgeLength   二维码的边长，二维码一般是正方形，所以输入一个边长就可以了
     * @return 成功生成返回true，生成失败返回false
     */
    public static boolean generateQrCodeImage(String fullFilePath, String anyValue, Integer edgeLength) {
        return generateQrCodeImage(fullFilePath, anyValue, edgeLength, ErrorCorrectionLevel.L);
    }

    /**
     * 向一个本地文件写入二维码图片，默认纠错率为传入的参数
     *
     * @param fullFilePath 文件的全路径
     * @param anyValue     任何需要变为二维码的字符串
     * @param edgeLength   二维码的边长，二维码一般是正方形，所以输入一个边长就可以了
     * @param level        二维码的生成质量，可以选高中低三种
     * @return 成功生成返回true，生成失败返回false
     */
    public static boolean generateQrCodeImage(String fullFilePath, String anyValue, Integer edgeLength, ErrorCorrectionLevel level) {
        String format = "png";
        Map<EncodeHintType, Object> hints = new HashMap<>(3);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, level);
        BitMatrix bitMatrix;
        try {
            bitMatrix = new MultiFormatWriter().encode(anyValue, BarcodeFormat.QR_CODE, edgeLength, edgeLength, hints);
        } catch (WriterException e) {
            e.printStackTrace();
            return false;
        }
        try (FileOutputStream fos = new FileOutputStream(fullFilePath)) {
            MatrixToImageWriter.writeToStream(bitMatrix, format, fos);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 解析二维码图片返回图片解析出来的字符串
     *
     * @param fullFilePath 二维码图片的本地路径
     * @return 二维码的内容
     */
    public static String parseQrCodeImageToText(String fullFilePath) {
        BufferedImage image;
        try {
            image = ImageIO.read(new File(fullFilePath));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Binarizer binarizer = new HybridBinarizer(source);
        BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
        Map<DecodeHintType, Object> hints = new HashMap<>(3);
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        Result result;
        try {
            result = new MultiFormatReader().decode(binaryBitmap, hints);
        } catch (NotFoundException e) {
            e.printStackTrace();
            return null;
        }
        return result.getText();
    }

    /**
     * 生成不带有底部文字的条形码
     *
     * @param fullFilePath 要输出的图片的本地路径
     * @param anyValue     任何想要输入的值但是仅限于0-9A-Z这种ASCII码值
     * @param width        生成的最终图片的宽度
     * @param height       生成的最终图片的高度
     * @return 生成成功返回true，生成失败返回false
     */
    public static boolean generateBarCodeImage(String fullFilePath, String anyValue, Integer width, Integer height) {
        String format = "png";
        Map<EncodeHintType, Object> hints = new HashMap<>(3);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        BitMatrix bitMatrix;
        try {
            bitMatrix = new MultiFormatWriter().encode(anyValue, BarcodeFormat.CODE_128, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
            return false;
        }
        try (FileOutputStream fos = new FileOutputStream(fullFilePath)) {
            MatrixToImageWriter.writeToStream(bitMatrix, format, fos);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 生成带有文字的条形码值
     *
     * @param fullFilePath 输出的本地文件路径
     * @param anyValue     任何ASCII值
     * @param width        图片的宽度
     * @param height       图片的高度
     * @return 生成成功返回true，生成失败返回false
     */
    public static boolean generateBarCodeImageWithText(String fullFilePath, String anyValue, Integer width, Integer height) {
        File targetFile = new File(fullFilePath);
        try {
            BrQrCodeUtil.brEncode(anyValue, BarcodeFormat.CODE_128, targetFile, width, height);
        } catch (IOException | WriterException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 解析条形码图片返回图片解析出来的字符串
     *
     * @param fullFilePath 条形码图片的本地路径
     * @return 条形码的内容
     */
    public static String parseBarCodeImageToText(String fullFilePath) {
        BufferedImage image;
        try {
            image = ImageIO.read(new File(fullFilePath));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Binarizer binarizer = new HybridBinarizer(source);
        BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
        Map<DecodeHintType, Object> hints = new HashMap<>(3);
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        Result result;
        try {
            result = new MultiFormatReader().decode(binaryBitmap, hints);
        } catch (NotFoundException e) {
            e.printStackTrace();
            return null;
        }
        return result.getText();
    }
}
